package hos.thread.executor;

import android.annotation.SuppressLint;
import android.util.Log;

import java.util.concurrent.Future;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import hos.thread.ThreadOption;
import hos.thread.hander.MH;

/**
 * <p>Title: ThreadExecutor </p>
 * <p>Description:  </p>
 * <p>Company: www.mapuni.com </p>
 *
 * @author : 蔡俊峰
 * @version : 1.0
 * @date : 2023/8/9 20:54
 */
public class ThreadExecutor extends ThreadPoolExecutor {

    private static final AtomicInteger threadId = new AtomicInteger(0);

    private ThreadExecutor() {
        this(Runtime.getRuntime().availableProcessors());
    }

    private ThreadExecutor(int cpuCount) {
        super(Math.max(4, Math.min(cpuCount + 1, 5)),
                cpuCount * 2 + 1,
                30L, TimeUnit.SECONDS, new PriorityBlockingQueue<Runnable>(), new ThreadFactory() {
                    @SuppressLint("DefaultLocale")
                    @Override
                    public Thread newThread(Runnable r) {
                        return new Thread(r, String.format("hos_io_%d", threadId.getAndIncrement()));
                    }
                });
    }

    private static volatile ThreadExecutor thread;

    public static ThreadExecutor thread() {
        if (thread == null) {
            synchronized (ThreadExecutor.class) {
                if (thread == null) {
                    thread = get();
                }
            }
        }
        return thread;
    }

    private static ThreadExecutor get() {
        return new ThreadExecutor();
    }

    public static ThreadExecutor run(Runnable runnable) {
        return thread.start(ThreadOption.Job.ON, runnable);
    }

    public static ThreadExecutor run(ThreadOption.Job job, Runnable runnable) {
        return thread.start(job, runnable);
    }

    public static boolean isMainThread() {
        return MH.isMainThread();
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        //监控线程池耗时任务,线程创建数量,正在运行的数量
        Log.d("Thread: ", "activeCount:"+getActiveCount());
        Log.d("Thread: ", "ThreadName" + Thread.currentThread().getName());
        if (r instanceof PriorityRunnable) {
            Log.d("Thread: ", "已执行完的任务的优先级是" + ((PriorityRunnable) r).getPriority());
        }
    }

    public ThreadExecutor postIo(int priority, Runnable runnable) {
        execute(new PriorityRunnable(priority, runnable));
        return this;
    }

    public ThreadExecutor postIo(Runnable runnable) {
        postIo(0, runnable);
        return this;
    }

    public ThreadExecutor postOnIo(Runnable runnable) {
        if (MH.isMainThread()) {
            postIo(runnable);
        } else {
            runnable.run();
        }
        return this;
    }

    @Override
    public Future<?> submit(Runnable task) {
        return super.submit(new PriorityRunnable(0, task));
    }

    public <T> Future<T> submit(Runnable task, T result) {
        return super.submit(new PriorityRunnable(0, task), result);
    }

    public <T> Future<T> submit(int priority, Runnable task, T result) {
        return super.submit(new PriorityRunnable(priority, task), result);
    }

    public Future<?> submit(int priority, Runnable task) {
        return super.submit(new PriorityRunnable(priority, task));
    }

    public ThreadExecutor start(Runnable runnable) {
        return start(ThreadOption.Job.ON, runnable);
    }

    public ThreadExecutor start(ThreadOption.Job job, Runnable runnable) {
        if (job == ThreadOption.Job.TO) {
            return postIo(runnable);
        }
        return postOnIo(runnable);
    }
}
